package com.bong.panpan.bongcharttools.server;

import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;

import com.bong.panpan.bongcharttools.custom.MyUtil;

import java.util.UUID;


/**
 * Created by panpan on 2017/10/24.
 */

public class HeartRateServer {
    public static String BLE_UUID_HEART_RATE_SERVICE = "0000180D-0000-1000-8000-00805f9b34fb";
    public static String BLE_UUID_HEART_RATE_MEASUREMENT_CHAR = "00002A37-0000-1000-8000-00805f9b34fb";
    public static String BLE_UUID_HEART_RATE_LOCATION_CHAR = "00002A38-0000-1000-8000-00805f9b34fb";
    public static final String DESC_UUID = "00002902-0000-1000-8000-00805f9b34fb";

    private final String TAG = "HeartRateServer";
    /**
     * < Bit mask used to extract the type of heart rate value. This is used to find if the received heart rate is a 16 bit value or an 8 bit value.
     */
    private final int HRM_FLAG_MASK_HR_16BIT = (0x01 << 0);

    /**
     * < Bit mask used to extract the presence of RR_INTERVALS. This is used to find if the received measurement includes RR_INTERVALS.
     */
    private final int HRM_FLAG_MASK_HR_RR_INT = (0x01 << 4);
    private final int BLE_HRS_C_RR_INTERVALS_MAX_CNT = 20;

    private BluetoothDevice device;
    private BluetoothGatt mBluetoothGatt;
    private bleHrsEvt evt_handler;
    private BluetoothGattService heartServer;
    private BluetoothGattCharacteristic measureChar;
    private BluetoothGattDescriptor measureDescriptor;
    private BluetoothGattCharacteristic locationChar;

    public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
        // Check if the event is on the link for this instance
        if (device == null || characteristic.getUuid().compareTo(UUID.fromString(BLE_UUID_HEART_RATE_LOCATION_CHAR)) != 0)
            return;
    }

    public void onHvx(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
        // Check if this is a heart rate notification.
        if (device == null || characteristic.getUuid().compareTo(UUID.fromString(BLE_UUID_HEART_RATE_MEASUREMENT_CHAR)) != 0)
            return;
        int index = 0;
        byte temp[] = characteristic.getValue();
        int data[] = MyUtil.byte2IntArray(temp);

        int rr_intervals_cnt = 0;
        int hr_value = 0;
        int rr_intervals[] = null;

        if ((data[index++] & HRM_FLAG_MASK_HR_16BIT) == 0) {
            // 8 Bit heart rate value received.
            hr_value = data[index++];  //lint !e415 suppress Lint Warning 415: Likely access out of bond
        } else {
            // 16 bit heart rate value received.
            hr_value = MyUtil.uint16_decode(temp[index], temp[index + 1]);
            index += 2;
        }

        if ((data[0] & HRM_FLAG_MASK_HR_RR_INT) != 0) {
            int i;
            /*lint --e{415} --e{416} --e{662} --e{661} -save suppress Warning 415: possible access out of bond */
            for (i = 0; i < BLE_HRS_C_RR_INTERVALS_MAX_CNT; i++) {
                rr_intervals = new int[BLE_HRS_C_RR_INTERVALS_MAX_CNT];
                if (index >= data.length) {
                    break;
                }
                rr_intervals[i] =
                        MyUtil.uint16_decode(temp[index], temp[index + 1]);
                index += 2;
            }
            /*lint -restore*/
            rr_intervals_cnt = i;
        }
        if (evt_handler != null)
            evt_handler.evtHandler(hr_value, rr_intervals, rr_intervals_cnt);

    }

    public void onDisconnected(BluetoothGatt gatt) {
        if (device != null && gatt.getDevice().getAddress().equals(device.getAddress())) {
            device = null;
            mBluetoothGatt = null;
            heartServer = null;
            measureChar = null;
            measureDescriptor = null;
            locationChar = null;
        }
    }


    public boolean bleHrsDiscEvt(BluetoothGatt gatt, int status) {
        // Check if the Heart Rate Service was discovered.
        if (status == BluetoothGatt.GATT_SUCCESS) {
            heartServer = gatt.getService(UUID.fromString(BLE_UUID_HEART_RATE_SERVICE));
            if (heartServer == null) {
                return false;
            }
            measureChar = heartServer.getCharacteristic(UUID.fromString(BLE_UUID_HEART_RATE_MEASUREMENT_CHAR));
            if (measureChar == null) {
                return false;
            }
            measureDescriptor = measureChar.getDescriptor(
                    UUID.fromString(DESC_UUID));
            if (measureDescriptor == null)
                return false;
            mBluetoothGatt = gatt;
            device = mBluetoothGatt.getDevice();
            locationChar = heartServer.getCharacteristic(UUID.fromString(BLE_UUID_HEART_RATE_LOCATION_CHAR));
            if (locationChar == null) {

            }
            return true;
        }
        return false;
    }

    public void bleHrsInit(bleHrsEvt evt_handler) {
        this.evt_handler = evt_handler;
    }


    public boolean bleHrsNotifEnable(boolean enable) {
        if (device == null)
            return false;
        if (enable) {
            if (!measureDescriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE))
                return false;
        } else {
            if (!measureDescriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE))
                return false;
        }
        if (!mBluetoothGatt.writeDescriptor(measureDescriptor))
            return false;
        if (!mBluetoothGatt.setCharacteristicNotification(measureChar, enable))
            return false;
        return true;
    }

    public boolean bleHrsReadLocation() {
        if (locationChar == null)
            return false;
        return mBluetoothGatt.readCharacteristic(locationChar);
    }

    public interface bleHrsEvt {
        void evtHandler(int hr_value, int rr_intervals[], int rr_intervals_cnt);
    }
}
